package com.xmu.prcs.dao.impl;

import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.type.Type;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.util.Assert;

import com.xmu.prcs.dao.GenericDao;
import com.xmu.prcs.util.PageBean;


/**
 * 泛型數據庫訪問接口的hibernate實現
 * @author frequent
 * @version 1.0,2012-3-20
 * @see GenericDao
 */
public class GenericDaoImpl<T> extends HibernateDaoSupport implements
		GenericDao<T> {

	static final Logger log = LoggerFactory.getLogger(GenericDaoImpl.class);

	private Class<T> _persistentClass;

	public GenericDaoImpl(Class<T> _persistenceClass) {
		this._persistentClass = _persistenceClass;
	}

	/**
	 * @see GenericDao#buildQuery(String)
	 */
	public String buildQuery(String query) {
		StringBuilder sb = new StringBuilder();
		sb.append("from ");
		sb.append(_persistentClass.getName());
		if (query != null && !query.equals("")) {
			sb.append(" as model where model.").append(query);
		}
		return sb.toString();
	}

	/**
	 * 
	 * @param countHql
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public Long count(String countHql) {
		List countlist = getHibernateTemplate().find(countHql);
		return (Long) countlist.get(0);
	}

	/**
	 * 
	 * @param countHql
	 * @param value
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public Long count(String countHql, Object value) {
		List countlist = getHibernateTemplate().find(countHql, value);
		String count = countlist.get(0).toString();
		return (new Long(Long.parseLong(count)));
	}

	/**
	 * 
	 * @param countHql
	 * @param values
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public Long count(String countHql, Object[] values) {
		List countlist = getHibernateTemplate().find(countHql, values);
		return (Long) countlist.get(0);
	}

	/**
	 * 
	 * @param sql
	 * @return
	 */
	public Long countByNativeSql(final String sql) {
		return countByNativeSql(sql, (Object[]) null, (Type[]) null);
	}

	/**
	 * 
	 * @param sql
	 * @param value
	 * @param type
	 * @return
	 */
	public Long countByNativeSql(final String sql, Object value, Type type) {
		return countByNativeSql(sql, new Object[] { value },
				new Type[] { type });
	}

	/**
	 * 
	 * @param sql
	 * @param values
	 * @param types
	 * @return
	 */
	public Long countByNativeSql(final String sql, final Object[] values,
			final Type[] types) {
		return (Long) getHibernateTemplate().execute(

		new HibernateCallback() {

			public Object doInHibernate(Session session)

			throws HibernateException {
				SQLQuery sqlQuery = session.createSQLQuery(sql);
				if (values != null && types != null && values.length > 0
						&& types.length > 0)
					sqlQuery.setParameters(values, types);
				return new Long(sqlQuery.uniqueResult().toString());

			}
		});
	}

	/**
	 * 创建Query对象.
	 * 对于需要first,max,fetchsize,cache,cacheRegion等诸多设置的函数,可以在返回Query后自行设置.
	 * 留意可以连续设置,如下：
	 * 
	 * <pre>
	 * service.getQuery(hql).setMaxResult(100).setCacheable(true).list();
	 * </pre>
	 * 
	 * 调用方式如下：
	 * 
	 * <pre>
	 *        service.createQuery(hql)
	 *        service.createQuery(hql,arg0);
	 *        service.createQuery(hql,arg0,arg1);
	 *        service.createQuery(hql,new Object[arg0,arg1,arg2])
	 * </pre>
	 * 
	 * @param values
	 *            可变参数.
	 */
	public Query createQuery(String hql, Object... values) {
		Assert.hasText(hql);
		Query query = getSession().createQuery(hql);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i, values[i]);
		}
		return query;
	}

	public void evict(T object) {
		// TODO Auto-generated method stub
		super.getHibernateTemplate().evict(object);
	}

	/**
	 * @see GenericDao#exists(Long)
	 */
	@SuppressWarnings("unchecked")
	public boolean exists(Integer id) {
		T entity = (T) super.getHibernateTemplate().get(_persistentClass, id);
		return entity != null;
	}

	/**
	 * 包裝hibernate的find函數以保證類型安全
	 * 
	 * @param query
	 *            HQL條件
	 * @return 查詢返回的數據列表
	 */
	@SuppressWarnings("unchecked")
	public List<T> find(String query) {
		return super.getHibernateTemplate().find(buildQuery(query));
	}

	/**
	 * 包裝hibernate的find函數以保證類型安全
	 * 
	 * @param query
	 *            HQL條件
	 * @param object
	 *            HibernateTemplate#find
	 * @return 查詢返回的數據列表
	 */
	@SuppressWarnings("unchecked")
	public List<T> find(String query, Object object) {
		return super.getHibernateTemplate().find(buildQuery(query), object);
	}

	/**
	 * 包裝hibernate的find函數以保證類型安全
	 * 
	 * @param query
	 *            HQL條件
	 * @param objects
	 *            org.springframework.orm.hibernate3.HibernateTemplate#find(String
	 *            ,Object[])
	 * @return 查詢返回的數據列表
	 */
	@SuppressWarnings("unchecked")
	public List<T> find(String query, Object[] objects) {
		return super.getHibernateTemplate().find(buildQuery(query), objects);
	}

	/**
	 * @see GenericDao#findByCriteria(DetachedCriteria)
	 */
	@SuppressWarnings("unchecked")
	public List<T> findByCriteria(DetachedCriteria criteria) {
		return super.getHibernateTemplate().findByCriteria(criteria);
	}

	@SuppressWarnings("unchecked")
	public List findByHql(String hql, Object[] values) {
		// TODO Auto-generated method stub
		List list = getHibernateTemplate().find(hql, values);
		return list;
	}

	@SuppressWarnings("unchecked")
	public List findByHql4Page(String hql, Object[] values, PageBean page) {
		// TODO Auto-generated method stub
		Query query = getHibernateTemplate().getSessionFactory()
				.getCurrentSession().createQuery(hql);
		if (page != null) {
			query.setFirstResult(page.getBeginIndex());
			query.setMaxResults(page.getPageSize());
		}
		if (values != null && values.length != 0) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		return query.list();
	}

	public void flush() {
		// TODO Auto-generated method stub
		super.getHibernateTemplate().flush();
	}

	/**
	 * @see GenericDao#get(Long)
	 */
	@SuppressWarnings("unchecked")
	public T get(Integer id) {

		T entity = (T) super.getHibernateTemplate().get(_persistentClass, id);

		if (entity == null) {
			// TODO: Error handle
		}
		return entity;
	}

	/**
	 * 
	 * @see GenericDao#getAll()
	 */
	public List<T> getAll() {
		return find(null);
	}

	/**
	 * @author ZL_BUG
	 * @see GenericDao#getAll(int, int)
	 */
	@SuppressWarnings("unchecked")
	public List<T> getAll(int index, int count) {

		final String hql = "from " + _persistentClass.getName();
		final int offset = index;
		final int length = count;

		List list = getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException {
				Query query = session.createQuery(hql);
				query.setFirstResult(offset);
				query.setMaxResults(length);
				List list = query.list();
				return list;
			}
		});
		if (list.isEmpty()) {
			// TODO: Error handle
		}
		return list;
	}

	@SuppressWarnings("unchecked")
	public List<T> getAllReverse(int index, int count) {

		final String hql = "from " + _persistentClass.getName();
		final int offset = index;
		final int length = count;

		List list = getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException {
				Query query = session.createQuery(hql);
				query.setFirstResult(offset);
				query.setMaxResults(length);
				List list = query.list();
				return list;
			}
		});
		if (list.isEmpty()) {
			// TODO: Error handle
		}
		return list;
	}
	/**
	 * @author ZL_BUG
	 * @see GenericDao#getCount()
	 */
	public int getCount() {

		String hql = "select count(*) from " + _persistentClass.getName();

		return Integer.parseInt((super.getHibernateTemplate().find(hql)
				.listIterator().next()).toString());
	}

	public Session openSession() {
		// TODO Auto-generated method stub
		return this.getHibernateTemplate().getSessionFactory()
				.getCurrentSession();
	}

	/**
	 * 
	 * @see GenericDao#remove(Long)
	 */
	public void remove(Integer id) {
		super.getHibernateTemplate().delete(this.get(id));
		System.out.println("delete success");
		super.getHibernateTemplate().flush();

	}

	public void removeWithoutFlush(Integer id) {
		super.getHibernateTemplate().delete(this.get(id));
	}

	/**
	 * @see GenericDao#save(Object)
	 */
	public void save(T object) {
		 System.out.println("generic save");
		// super.getSession().merge(object);//
		super.getHibernateTemplate().saveOrUpdate(object);
		//System.out.println("saveOrUpdate success");
		super.getHibernateTemplate().flush();
	}

	/**
	 * 
	 * @see GenericDao#update(Object)
	 */
	public void update(T object) {
		// super.getSession().merge(object);//
		// super.getSession().refresh(object);
		System.out.println("generic update");
		super.getHibernateTemplate().merge(object);
		super.getHibernateTemplate().update(object);

	}

	/**
	 * @author hjp
	 * 
	 * @see GenericDao#updateWithoutMerge(Object)
	 * @param object
	 */
	public void updateWithoutMerge(T object) {
		super.getHibernateTemplate().update(object);
	}
	
	public void merge(T object){
		super.getHibernateTemplate().merge(object);
	}
	
}
